package util;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * ClassName: DBUCoon
 * Description:
 *
 * @Author zjl
 * @Create 2025/02/24 19:15
 * @Version 1.0
 */
public class DBCoon {
    /**
     * 连接驱动程序
     */
    private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    /**
     * 连接URL
     */
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/jdbc_test?useUnicode=true;characterEncoding=utf8;serverTimezone=Asia/Shanghai";
    /**
     * 帐号
     */
    private static final String USER = "root";
    /**
     * 密码
     */
    private static final String PASS = "123456";

    static {
        /*
         * 加载驱动程序
         */
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            System.out.println("加载驱动程序失败...");
            e.printStackTrace();
        }
    }

    /**
     * 获取连接对象 -- Java程序 与 数据库之间的桥梁
     *
     * @return
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(URL, USER, PASS);
        } catch (SQLException e) {
            System.out.println("获取连接对象失败...");
            e.printStackTrace();
        }
        return conn;
    }


    /**
     * 关闭相关的 JDBC 对象
     * <p>
     * DriverManager：驱动管理对象，获取连接对象
     * <p>
     * DriverManager.getConnection(URL, USER, PASS);
     * <p>
     * ResultSet：结果集对象 用于接收查询数据时，返回的结果
     * <p>
     * Statement：语句对象 用于执行SQL语句（PreparedStatement、CallableStatement）
     * 增、删、改：executeUpdate() 查询：executeQuery()
     * <p>
     * <p>
     * Connection：连接对象 建立JAVA程序与数据库之间的桥梁
     *
     * @param rst
     * @param stmt 父类对象可以接收子类对象 - 多态
     * @param conn
     */
    public static void close(ResultSet rst, Statement stmt, Connection conn) {
        if (rst != null) {
            try {
                rst.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        System.out.println(DBCoon.getConnection());
    }

        static Properties prop = new Properties();


        /**
         * 用于执行sql中select语句查询所有,可以加条件查询
         *
         * @param sql        预定义sql语句
         * @param clazz      实体类的Class对象
         * @param parameters 根据条件查询的条件可变参数
         * @param <T>        实体类
         * @return 返回一个结果集
         */
        public static <T> List<T> list(String sql, Class<T> clazz, Object... parameters) {
            List<T> list = new ArrayList<>();
            try (Connection con = DBCoon.getConnection()) {
                try (PreparedStatement stmt = con.prepareStatement(sql)) {
                    /*动态替换参数*/
                    int index = 1;
                    for (Object param : parameters) {
                        stmt.setObject(index++, param);
                    }
                    ResultSet rs = stmt.executeQuery();
                    while (rs.next()) {
                        list.add(getObject(clazz, rs));
                    }
                } catch (InstantiationException e) {
                    throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
                }
            } catch (SQLException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
            }
            return list;
        }

        /**
         * 按条件查询一个唯一实体对象
         *
         * @param sql        预定义sql语句
         * @param clazz      实体类的Class对象
         * @param parameters 根据条件查询的条件可变参数
         * @param <T>        实体类
         * @return 返回一个唯一实体对象
         */
        public static <T> T one(String sql, Class<T> clazz, Object... parameters) {
            T t = null;
            try (Connection con = DBCoon.getConnection()) {
                try (PreparedStatement stmt = con.prepareStatement(sql)) {
                    /*动态替换参数*/
                    int index = 1;
                    for (Object param : parameters) {
                        stmt.setObject(index++, param);
                    }
                    ResultSet rs = stmt.executeQuery();
                    if (rs.next()) {
                        t = getObject(clazz, rs);
                    }
                } catch (InstantiationException e) {
                    throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
                }
            } catch (SQLException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException("数据表中的数据映射到实现类对象失败:" + e.getMessage());
            }
            return t;
        }

        /**
         * 更新数据表的操作，支持动态可变参数
         *
         * @param sql        数据库中的update,insert,delete操作的SQL语句
         * @param parameters 用于预处理sql语句的可变参数
         * @return 返回受影响的行数
         */
        public static int update(String sql, Object... parameters) {
            return update( getConnection(),sql,  parameters);
        }

        /**
         * 更新数据表的操作，支持动态可变参数
         *
         * @param sql        数据库中的update,insert,delete操作的SQL语句
         * @param parameters 用于预处理sql语句的可变参数
         * @return 返回受影响的行数
         */
        public static int update(Connection conn, String sql, Object... parameters) {
            int row = 0;
            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
                /*动态替换参数*/
                int index = 1;
                for (Object param : parameters) {
                    stmt.setObject(index++, param);
                }
                row = stmt.executeUpdate();
            } catch (SQLException e) {
                throw new RuntimeException("数据表更新失败:" + e.getMessage());
            }
            return row;
        }


        /**
         * 根据 结果集，映射成一个java实体对象
         *
         * @param clazz
         * @param rs
         * @param <T>
         * @return
         * @throws InstantiationException
         * @throws IllegalAccessException
         * @throws SQLException
         * @throws InvocationTargetException
         */
        private static <T> T getObject(Class<T> clazz, ResultSet rs) throws InstantiationException, IllegalAccessException, SQLException, InvocationTargetException {
            T t = clazz.newInstance();
            ResultSetMetaData metaData = rs.getMetaData();//获取结果集的元数据对象
            Method[] methods = clazz.getDeclaredMethods();//获取实体类中所有方法对象
            for (int i = 1; i <= metaData.getColumnCount(); i++)//根据结果集的列的数据循环
            {
                String fieldName = metaData.getColumnName(i);//获取第一个列的列名（列：数据库表中的列名)
//            int index=0;
//            while(index<fieldName.length()){
//                index = fieldName.indexOf("_",0);
//                if(index==1)
//                    break;
//                String w = fieldName.substring(index+1,index+2).toUpperCase();
//                fieldName = fieldName.substring(0,index)+w+fieldName.substring(index+2);
//            }
                String methodName = "set" + fieldName.toUpperCase().substring(0, 1)
                        + fieldName.substring(1);//拼接set方法名(比：age=>setAge, userName=>setUserName
                for (Method m : methods) {
                    if (m.getName().equals(methodName)) {
                        m.invoke(t, rs.getObject(fieldName));//执行指定方法
                        break;
                    }
                }
                //正常方法执行  对象.方法名(实参)如： question.setName("axxx")
                //反向执行方法  方法对象.invoke(对象,实参)  如： mothod.invoke(qusetion,"axxx")
            }
            return t;
        }

}
